package servidor;


import cliente.gui.LoginGUI;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import org.hibernate.exception.ConstraintViolationException;

import dao.PerguntaDAO;
import dao.UsuarioDAO;
import java.util.List;
import objetos.*;



public class AppServidor {
        protected static int PORTA = 6790;
	@SuppressWarnings("unchecked")
	public static void main(String argv[]) throws Exception {
            ServerSocket servidor = new ServerSocket(PORTA);
            System.out.println("Servidor Iniciado, aguardando conexao...\n\n");
            while(true) {
                Socket conexao = servidor.accept();

                // Conexao para receber os dados do cliente
                ObjectInputStream in 	= new ObjectInputStream(conexao.getInputStream());
                // Conexao para enviar os dados do cliente
                ObjectOutputStream out 	= new ObjectOutputStream(conexao.getOutputStream());

                ArrayList<Object> objetoRecebido = (ArrayList<Object>) in.readObject();
                String cabecalho = (String) objetoRecebido.get(0);

                if (cabecalho.equals       ("cadastroUsuario")) {
                    // objetoRecebido.get(1) = Usuario;
                    System.out.println("["+conexao.getInetAddress()+"]--Recebida solicitacao para cadastro de usuario");
                    cadastrarUsuario((Usuario)objetoRecebido.get(1), out);
                } else if (cabecalho.equals("loginUsuario")) {
                    System.out.println("["+conexao.getInetAddress()+"]--Recebida solicitacao de login");
                    String matricula = (String) objetoRecebido.get(1);
                    String senha = (String) objetoRecebido.get(2);
                    loginUsuario(matricula,senha,out);
                } else if (cabecalho.equals("EnviarPergunta")) {
                    System.out.println("["+conexao.getInetAddress()+"]--Recebida solicitacao para enviar pergunta");
                    Pergunta pergunta = (Pergunta) objetoRecebido.get(1);
                    enviarPergunta(pergunta,out);
                } else if(cabecalho.equals("GetMinhasPerguntas")) {
                    System.out.println("["+conexao.getInetAddress()+"]--Recebida solicitacao para pegar Minhas perguntas");
                    String matricula = (String) objetoRecebido.get(1);
                    getMinhasPerguntas(matricula,out);
                } else if(cabecalho.equals("GetUsuariosCadastrados")) {
                    System.out.println("["+conexao.getInetAddress()+"]--Recebida solicitacao para pegar Todos usuarios do sistema");
                    getUsuariosCadastrados(out);
                } else if (cabecalho.equals("AtualizarUsuario")) {
                    System.out.println("["+conexao.getInetAddress()+"]--Recebida solicitacao para atualizar Usuario");
                    Usuario usuario = (Usuario)objetoRecebido.get(1);
                    atualizarUsuario(usuario,out);
                }
                in.close();
                out.close();
            }
            
	}

    /** Se nao existir ninguem cadastrado no BD,
     * o primeiro cadastro efetuado vai ser Administrador(Professor)
     * isPendente=false && isAdmin=true
     * Senao, o cadastro vai ser efetuado normalmente
     */
    private static void cadastrarUsuario(Usuario usuario, ObjectOutputStream out) {
            ArrayList<Object> objetoPacote = new ArrayList<Object>();
            try {
                try {
                    //Objeto que vai ser transferido pelo socket
                    UsuarioDAO userDao = new UsuarioDAO();

                    if(userDao.getTotalUsuarios() == 0L) {
                            // Ninguem foi cadastrado ainda
                            usuario.setAdmin(true);
                            usuario.setPendente(false);
                            userDao.salvar(usuario);
                            userDao.atualizar(usuario);

                            // Responder ao cliente que o novo usuario eh admin
                            // e que foi adicionado com sucesso

                            objetoPacote.add((String) "cadastroUsuario sucesso");
                            objetoPacote.add((String) "Novo usuario administrador cadastrado");
                            out.writeObject(objetoPacote);
                    }
                    else {
                            usuario.setPendente(true);
                            usuario.setAdmin(false);
                            userDao.salvar(usuario);
                            userDao.atualizar(usuario);
                            objetoPacote.add("cadastroUsuario sucesso");
                            objetoPacote.add(
                                            "Novo usuario cadastrado, aguade ate que \n" +
                                            "o administrador aceite sua solicitacao");
                            out.writeObject(objetoPacote);
                    }
                }catch(ConstraintViolationException e) {
                    objetoPacote.add("cadastroUsuario erro");
                    objetoPacote.add(
                                    "Erro: Matricula informada ja esta em uso \n" +
                                    "Caso voce ja fez o cadastro, aguarde ate \n" +
                                    "que o administrador aceite sua solicitacao");
                    out.writeObject(objetoPacote);
                }catch(Exception e) {
                    objetoPacote.add("cadastroUsuario erro");
                    objetoPacote.add(e.getMessage());
                    out.writeObject(objetoPacote);
                    e.printStackTrace();
                }
            }catch(Exception e) {
                e.printStackTrace();
            }
       }

    private static void loginUsuario(String matricula, String senha, ObjectOutputStream out) {
        ArrayList<Object> objetoPacote = new ArrayList<Object>();
        try {
            util.VerificaLogin vl = new util.VerificaLogin(matricula,senha);
            Usuario user = vl.validate();
            if (user == null) {
                objetoPacote.add("erro");
                objetoPacote.add("Matricula e/ou senha nao conferem");
                out.writeObject(objetoPacote);
            }
            else if(user.isPendente()==true) {
                System.out.println(user.isPendente());
                objetoPacote.add("erro");
                objetoPacote.add("Cadastro pendente. Aguarde o administraor aceitar sua solicitacao");
                out.writeObject(objetoPacote);
            }
            else {
                objetoPacote.add("sucesso");
                objetoPacote.add(user);
                out.writeObject(objetoPacote);
            }
        }catch(Exception e) {
                e.printStackTrace();
        }
    }

    private static void enviarPergunta(Pergunta pergunta, ObjectOutputStream out) {
        ArrayList<Object> objetoPacote = new ArrayList<Object>();
        try {
            try {
                PerguntaDAO perguntaDao = new PerguntaDAO();
                perguntaDao.salvar(pergunta);
                perguntaDao.atualizar(pergunta);
                objetoPacote.add("sucesso");
                out.writeObject(objetoPacote);
            } catch(Exception e) {
                objetoPacote.add("erro");
                objetoPacote.add(e.getMessage());
                out.writeObject(objetoPacote);
                e.printStackTrace();
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    private static void getMinhasPerguntas(String matricula, ObjectOutputStream out) {
        ArrayList<Object> objetoPacote = new ArrayList<Object>();
        try {
            try {
                UsuarioDAO userDao = new UsuarioDAO();
                Usuario user = (Usuario) userDao.buscaPorMatricula(matricula);
                objetoPacote.add("sucesso");
                System.out.println(user.getPerguntas().get(0).getMensagem());
                //System.out.println(user.getPerguntas().get(1).getTitulo());
                objetoPacote.add(user.getPerguntas());
                //objetoPacote.add(user.getRespostas());
                out.writeObject(objetoPacote);
            } catch(Exception e) {
                objetoPacote.add("erro");
                objetoPacote.add(e.getMessage());
                out.writeObject(objetoPacote);
                e.printStackTrace();
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    private static void getUsuariosCadastrados(ObjectOutputStream out) {
        ArrayList<Object> objetoPacote = new ArrayList<Object>();
        try {
            try {
                UsuarioDAO userDao = new UsuarioDAO();
                List usuarios = (List) userDao.buscarTodosUsuariosCadastrados();
                objetoPacote.add("sucesso");
                objetoPacote.add(usuarios);
                
                out.writeObject(objetoPacote);
            } catch(Exception e) {
                objetoPacote.add("erro");
                objetoPacote.add(e.getMessage());
                out.writeObject(objetoPacote);
                e.printStackTrace();
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    private static void atualizarUsuario(Usuario usuario, ObjectOutputStream out) {
        ArrayList<Object> objetoPacote = new ArrayList<Object>();
        try {
            UsuarioDAO userDao = new UsuarioDAO();
            System.out.println(usuario.getEmail());
            System.out.println(usuario.getMatricula());
            System.out.println(usuario.getNomeCompleto());
            System.out.println(usuario.isAdmin());
            System.out.println(usuario.getPontosExtra());
            userDao.atualizar(usuario);
            objetoPacote.add("sucesso");
            out.writeObject(objetoPacote);
        }catch(Exception e) {
            objetoPacote.add("erro");
            e.printStackTrace();
        }

        
    }
}


